/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.widget;

import java.lang.reflect.Field;
import java.util.ArrayList;

import lt.marsrutai.mobile.android.R;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;

/**
 * Delegates all motion events to scroll view until scroll view is fully scrolled. This is useful when ViewPager holds
 * horizontal scroll views.
 * 
 * This class makes couple of assumptions. Items which are held in ViewPager are of Fragment class. View of current
 * fragment has a view with HORIZONTAL_SCROLL_VIEW_ID and is of HorizontalScrollView class. And lastly a view with id
 * HORIZONTAL_SCROLL_VIEW_ID has a child.
 * 
 * Checks are made in place so that no exceptions would be thrown if any of above assumptions are not met.
 * 
 * @author Martynas
 * 
 */
public class HorizontalScrollViewAwarePager extends ViewPager {

    private static final Logger logger = LoggerFactory.getLogger("HorizontalScrollViewAwarePager");

    private static final int HORIZONTAL_SCROLL_VIEW_ID = R.id.stop_times_horizontal_scroll_view;

    public HorizontalScrollViewAwarePager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        View currentView = getCurrentView();
        if (null != currentView) {
            HorizontalScrollView horizontalScrollView = (HorizontalScrollView) currentView.findViewById(HORIZONTAL_SCROLL_VIEW_ID);

            if (null != horizontalScrollView) {
                View holder = horizontalScrollView.getChildAt(0);

                // Give all motions events to scroll view, until it is fully scrolled.
                // Only turn the page when child is fully scrolled.
                if (horizontalScrollView.getWidth() + horizontalScrollView.getScrollX() < holder.getWidth()) {
                    return false;
                }
            }

        }
        return super.onInterceptTouchEvent(event);
    }

    /**
     * Gets current focused View of this ViewPager.
     * 
     * @return current focused View
     */
    public View getCurrentView() {
        Object currentObject = getCurrentObject();

        if (!(currentObject instanceof Fragment)) {
            return null;
        }

        return ((Fragment) currentObject).getView();
    }

    /**
     * Gets current object of this ViewPager. No API exists for this, so we take a peek to the private variables of the
     * ViewPager class.
     * 
     * @return
     */
    public Object getCurrentObject() {
        try {
            final Field itemsField = ViewPager.class.getDeclaredField("mItems");
            itemsField.setAccessible(true);

            @SuppressWarnings("unchecked")
            final ArrayList<Object> items = (ArrayList<Object>) itemsField.get(this);

            final int currentItemIndex = getCurrentItem();
            if (currentItemIndex < 0 || currentItemIndex >= items.size()) {
                return null;
            }

            final Object infoItem = items.get(currentItemIndex);

            final Class<?> itemInfoClass = findItemInfoClass(ViewPager.class.getDeclaredClasses());

            final Field objectField = itemInfoClass.getDeclaredField("object");
            objectField.setAccessible(true);
            return objectField.get(infoItem);

        }
        catch (NoSuchFieldException e) {
            logger.error(e.toString());
        }
        catch (IllegalArgumentException e) {
            logger.error(e.toString());
        }
        catch (IllegalAccessException e) {
            logger.error(e.toString());
        }

        return null;
    }

    private Class<?> findItemInfoClass(final Class<?>[] classes) throws IllegalArgumentException {
        for (int i = 0; i < classes.length; i++) {
            if (classes[i].getSimpleName().equals("ItemInfo")) {
                return classes[i];
            }
        }

        throw new IllegalArgumentException("cannot find class ItemInfo");
    }

}
